
#include <gfx/gl20/program_gl20.h>
#include <gfx/gl20/shader_gl20.h>
#include <assert.h>


ceProgramGL20::ceProgramGL20 ()
	: iProgram ()
{
	CE_OBJECT_CONSTR
	_name = glCreateProgram();

	PrepareBindings (ceProgramParameterNameManager::Get ()->GetNumberOfNames ());
}

ceProgramGL20::~ceProgramGL20()
{
	glDeleteProgram (_name);
	ClearShaders();
}

void ceProgramGL20::ClearParameterBindings ()
{
	for (int i=0, j=_parameterBindings.size(); i<j; ++i)
		{
			ceProgramParameterGL20* param = _parameterBindings[i];
			CE_UNSET(param);
		}

	_parameterBindings.clear();
}

GLuint ceProgramGL20::GetName () const
{
	return _name;
}

void ceProgramGL20::ClearShaders()
{
	if (_name)
		{
			glDeleteProgram (_name);
		}

	ClearParameterBindings();
	_name = glCreateProgram();
}

void ceProgramGL20::AttachShader (iShader* shader)
{
	assert (_name != 0);
	if (!shader)
		{
			return;
		}
	ceShaderGL20* glShader = static_cast<ceShaderGL20*>(shader);
	glAttachShader (_name, glShader->GetName ());
}

void ceProgramGL20::DetachShader (iShader* shader)
{
	assert (_name != 0);
	if (!shader)
		{
			return;
		}
	ceShaderGL20* glShader = static_cast<ceShaderGL20*>(shader);
	glDetachShader (_name, glShader->GetName ());
}

bool ceProgramGL20::Link ()
{
	assert (_name != 0);
  glLinkProgram (_name);
	GLint linkState;
	glGetProgramiv (_name, GL_LINK_STATUS, &linkState);
	return linkState == GL_TRUE;
}

std::string ceProgramGL20::GetLinkInfoLog () const
{
	assert (_name != 0);
	static char infoLog[1024];
	GLsizei size;
	glGetProgramInfoLog(_name, 1024, &size, (GLchar*)infoLog);
	infoLog[size] = '\0';
	return std::string(infoLog);
}

void ceProgramGL20::Bind()
{
	assert (_name);

	glUseProgram (_name);
}

void ceProgramGL20::PrepareBindings (unsigned numberOfBindings)
{
	// fill up the missing binding names (ofcourse they are not initialize)
	int missing = numberOfBindings - _parameterBindings.size ();
	for (int i=0; i<missing; i++)
		{
			_parameterBindings.push_back(0);
		}
}

void ceProgramGL20::RegisterSemantic(const ceProgramParameterName& name, const std::string& parameterName)
{
	PrepareBindings (ceProgramParameterNameManager::Get ()->GetNumberOfNames ());

	ceProgramParameterGL20* param = GetParameterByName(parameterName);
  printf ("Parameter: [%d] %s => %s => %p\n", name.GetId(), name.GetName(), parameterName.c_str(), param);
  fflush (stdout);

	_parameterBindings[name.GetId()] = param;
}


ceProgramParameterGL20* ceProgramGL20::GetParameterByName(const std::string &name)
{
	assert (_name);

	int loc = glGetUniformLocation(_name, name.c_str());
	if (loc != -1)
		{
			return new ceProgramParameterGL20 (loc, PPT_Uniform);
		}

	loc = glGetAttribLocation(_name, name.c_str ());
	if (loc != -1)
		{
			return new ceProgramParameterGL20 (loc, PPT_Attribute);
		}

	return 0;
}

ceProgramParameterGL20* ceProgramGL20::GetParameter(const ceProgramParameterName& name)
{
	if (name.GetId() >= _parameterBindings.size()) return 0;
	return _parameterBindings[name.GetId ()];
}
